package com.nextive.weightlogger.activity;

import static com.nextive.weightlogger.util.DialogUtil.showMessage;
import static com.nextive.weightlogger.util.StringUtil.validateEmailAddress;

import java.util.ArrayList;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.InputType;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.nextive.weightlogger.R;
import com.nextive.weightlogger.WeightUnit;
import com.nextive.weightlogger.dao.SettingsDao;
import com.nextive.weightlogger.dao.WeightLogDao;
import com.nextive.weightlogger.dto.Settings;
import com.nextive.weightlogger.util.ContentUtil;

/**
 * Lets the user set his name, email address, default recipient for his shares,
 * and weight unit to use for inputs and display.
 * 
 * @author Federico Baseggio <fedebaseggio@gmail.com>
 */
public class SettingsActivity extends BaseActivity {
	// Constant used to identify the source of calls to the callback method
	// onActivityResult().
	private final int ACTIVITY_RESULT_PICK = 1;
	private final int ACTIVITY_RESULT_CREATE = 2;
	
	// Widgets
	private EditText name;
	private EditText email;
	private TextView defaultRecipientEmail;
	private TextView unit;
	
	private Settings settings;
	private SettingsDao settingsDao;
	private String pickedContactEmailAddress;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		settingsDao = new SettingsDao(this);
		
		setContentView(R.layout.settings);
		name = (EditText) findViewById(R.id.name);
		email = (EditText) findViewById(R.id.email);
		defaultRecipientEmail = (TextView) findViewById(R.id.defaultRecipientField);
		unit = (TextView) findViewById(R.id.unitField);
		
		name.setInputType(InputType.TYPE_CLASS_TEXT
				| InputType.TYPE_TEXT_VARIATION_PERSON_NAME);
		email.setInputType(InputType.TYPE_CLASS_TEXT
				| InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);

		LinearLayout defaultRecipientLayout = (LinearLayout) findViewById(R.id.defaultRecipientLayout);
		defaultRecipientLayout.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				promptForRecipientType();
			}
		});

		LinearLayout unitLayout = (LinearLayout) findViewById(R.id.unitLayout);
		unitLayout.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				promptForUnit();
			}
		});
	}
	
	/**
	 * Click callback method for the save button. 
	 * 
	 * @param v The button that was clicked.
	 */
	public void onSaveClick(View v) {
		if (validate(true))
		{
			moveToNextActivity();
		}
	}
	
	/**
	 * Displays a dialog for the user to pick a type of recipient, either self,
	 * pick a contact from the phone, or create a new contact on the phone.
	 */
	private void promptForRecipientType() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);

		builder.setTitle(R.string.settings_default_recipient_email);

		// Dialog items
		String self = getString(R.string.settings_recipient_self);
		String contact = getString(R.string.settings_recipient_contact);
		String newContact = getString(R.string.settings_recipient_new);
		CharSequence[] items = { self, contact, newContact };

		builder.setItems(items, new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int item) {
				switch (item) {
				case 0:
					// Self
					settings.setDefaultRecipientType(Settings.RecipientType.SELF);
					updateDisplay();
					break;
				case 1:
					// Pick a contact
					promptForContact();
					break;
				case 2:
					// Create new contact
					promptForCreateContact();
					break;
				}
			}
		});
		AlertDialog alert = builder.create();
		alert.show();
	}

	/**
	 * Displays a dialog for the user to pick a weight unit.
	 */
	private void promptForUnit() {
		ArrayList<CharSequence> items = new ArrayList<CharSequence>();
		for (WeightUnit unit : WeightUnit.values()) {
			items.add(getUnitDisplayName(unit));
		}

		AlertDialog.Builder builder = new AlertDialog.Builder(this);

		builder.setTitle(R.string.settings_unit);
		int selectedItemIndex = -1;
		if (settings.getUnit() != null) {
			selectedItemIndex = settings.getUnit().ordinal();
		}
		builder.setSingleChoiceItems(items.toArray(new CharSequence[] {}),
				selectedItemIndex, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int item) {
						settings.setUnit(WeightUnit.values()[item]);
						updateDisplay();
						dialog.dismiss();
					}
				});
		AlertDialog alert = builder.create();
		alert.show();
	}
	
	/**
	 * Moves on to next activity in the flow.
	 */
	private void moveToNextActivity()
	{
		// Decide what's the next activity in the flow and move on to it
		if (getIntent().getBooleanExtra(INTENT_EXTRA_FIRST_ACTIVITY, false))
		{
			// This activity was started cause settings were incomplete
			startActivity(new Intent(this, WeightHistoryActivity.class));
		}
		else
		{
			// This activity was started by user's choice. Let's get back to the
			// activity that was on top before.
			finish();
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
    	
		loadSettings();

		// Check if we're back from the Contacts activity after creating a new
		// contact or picking one.
		if (pickedContactEmailAddress != null)
		{
			settings.setDefaultRecipientType(Settings.RecipientType.CONTACT);
			settings.setDefaultRecipientEmail(pickedContactEmailAddress);
			updateDisplay();
			pickedContactEmailAddress = null;
		}
	}
	
	@Override
	protected void onPause() {
		super.onPause();

		saveSettings();
	}

	/**
	 * Starts the contact list activity for the user to pick a contact.
	 */
	private void promptForContact()
	{
		Intent intent = new Intent(Intent.ACTION_PICK,
				ContactsContract.Contacts.CONTENT_URI);
		startActivityForResult(intent, ACTIVITY_RESULT_PICK);
	}

	/**
	 * Starts the create contact activity for the user create a new contact.
	 */
	private void promptForCreateContact()
	{
		Intent intent = new Intent(Intent.ACTION_INSERT,
				ContactsContract.Contacts.CONTENT_URI);
		startActivityForResult(intent, ACTIVITY_RESULT_CREATE);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	    if(resultCode == RESULT_OK) {
	    	switch (requestCode)
	    	{
	    	case ACTIVITY_RESULT_PICK:
	    	case ACTIVITY_RESULT_CREATE:
	    		onContactPicked(data);
	    		break;
	    	}
	    }
	}
	
	/**
	 * Invoked when the user either picks a contact in the contact list
	 * activity, or created a contact in the create contact activity.
	 * 
	 * @param data
	 *            The intent returned by the activity started earlier by this
	 *            activity.
	 */
	private void onContactPicked(Intent data){
        ContentUtil contentUtil = new ContentUtil(getContentResolver());
    	String emailAddress = contentUtil.getEmail(data.getData());
        if (emailAddress == null)
        {
			showMessage(this, R.string.settings_contact_no_email,
					defaultRecipientEmail);
        }
        else
        {
        	// Keep the email address to set it in onResume
        	pickedContactEmailAddress = emailAddress;
        }
	}

	/**
	 * Validates user input.
	 * 
	 * @param showErrors
	 *            Whether to show errors to the user if settings are not valid
	 * @return True if settings are valid, false otherwise
	 */
	private boolean validate(boolean showErrors) {
		if (name.getText().length() == 0) {
			if (showErrors) {
				showMessage(this, R.string.settings_invalid_name, name);
			}
			return false;
		} else if (!validateEmailAddress(email.getText().toString())) {
			if (showErrors) {
				showMessage(this, R.string.settings_invalid_email, email);
			}
			return false;
		} else if (settings.getDefaultRecipientType() == null) {
			if (showErrors) {
				showMessage(this, R.string.settings_invalid_recipient_type,
						defaultRecipientEmail);
			}
			return false;
		} else if (settings.getDefaultRecipientType() == Settings.RecipientType.CONTACT && !validateEmailAddress(settings.getDefaultRecipientEmail())) {
			if (showErrors) {
				showMessage(this, R.string.settings_invalid_recipient_email,
						defaultRecipientEmail);
			}
			return false;
		} else if (settings.getUnit() == null) {
			if (showErrors) {
				showMessage(this, R.string.settings_unit_not_selected, unit);
			}
			return false;
		}
		return true;
	}
	
	/**
	 * Saves settings from user input.
	 */
	private void saveSettings()
	{
		setSettingsFromDisplay();
		settingsDao.saveSettings(settings, validate(false));
	}
	
	/**
	 * Loads settings and populates the input fields.
	 */
	private void loadSettings()
	{
		settings = settingsDao.readSettings();

		name.setText(settings.getName());
		email.setText(settings.getEmail());

		updateDisplay();
	}

	/**
	 * Store input fields into {@link #settings} entries.
	 */
	private void setSettingsFromDisplay()
	{
		settings.setName(name.getText().toString());
		settings.setEmail(email.getText().toString());
	}
	
	/**
	 * Updates the text of the widgets based on the settings set, except from
	 * EditText views.
	 */
	private void updateDisplay()
	{
		if (settings.getDefaultRecipientEmail() == null) 
		{
			defaultRecipientEmail.setText(R.string.data_not_set);
		} 
		else if (settings.getDefaultRecipientType() == Settings.RecipientType.SELF)
		{
			defaultRecipientEmail.setText(R.string.settings_recipient_self);
		}
		else 
		{
			defaultRecipientEmail.setText(settings.getDefaultRecipientEmail());
		}
		
		if (settings.getUnit() == null)
		{
			unit.setText(R.string.data_not_set);
		}
		else
		{
			unit.setText(getUnitDisplayName(settings.getUnit()));
		}
	}
	
	/**
	 * Retrieves the display name of the specified unit.
	 * 
	 * @param unit
	 *            The weight unit.
	 * @return The display name of the specified unit.
	 */
	private String getUnitDisplayName(WeightUnit unit) {
		return getResources().getStringArray(R.array.weight_units)[unit
				.getResourceItemIndex()];
	}
}